package cn.wolfcode.car.business.service.impl;

import cn.wolfcode.car.base.domain.User;
import cn.wolfcode.car.base.service.IUserService;
import cn.wolfcode.car.business.domain.BpmnInfo;
import cn.wolfcode.car.business.domain.CarPackageAudit;
import cn.wolfcode.car.business.domain.ServiceItem;
import cn.wolfcode.car.business.mapper.CarPackageAuditMapper;
import cn.wolfcode.car.business.query.CarPackageAuditQuery;
import cn.wolfcode.car.business.service.IBpmnInfoService;
import cn.wolfcode.car.business.service.ICarPackageAuditService;
import cn.wolfcode.car.business.service.IServiceItemService;
import cn.wolfcode.car.common.base.page.TablePage;
import cn.wolfcode.car.common.base.page.TablePageInfo;
import cn.wolfcode.car.common.exception.BusinessException;
import cn.wolfcode.car.common.util.Convert;
import cn.wolfcode.car.common.util.StringUtils;
import cn.wolfcode.car.shiro.ShiroUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.activiti.bpmn.model.BpmnModel;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.activiti.image.impl.DefaultProcessDiagramGenerator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

@Service
@Transactional
public class CarPackageAuditServiceImpl extends ServiceImpl<CarPackageAuditMapper, CarPackageAudit> implements ICarPackageAuditService {

    @Autowired
    private CarPackageAuditMapper carPackageAuditMapper;

    @Autowired
    private IServiceItemService serviceItemService;

    @Autowired
    private IBpmnInfoService bpmnInfoService;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private IUserService userService;

    @Autowired
    private RepositoryService repositoryService;

    @Autowired
    private TaskService taskService;

    @Override
    public TablePage<CarPackageAudit> query(CarPackageAuditQuery qo) {
        Page<CarPackageAudit> page = new Page<>(qo.getPageNum(), qo.getPageSize());
        QueryWrapper<CarPackageAudit> wrapper = Wrappers.<CarPackageAudit>query();
        wrapper.ge(StringUtils.isNotNull(qo.getBeginTime()),"create_time",qo.getBeginTime());
        wrapper.le(StringUtils.isNotNull(qo.getEndTime()),"create_time",qo.getEndTime());
        wrapper.eq(StringUtils.isNotNull(qo.getAuditorId()),"auditor_id",qo.getAuditorId());
        wrapper.like(StringUtils.isNotEmpty(qo.getAuditorName()),"info",qo.getAuditorName());
        carPackageAuditMapper.selectPage(page, wrapper);
        List<CarPackageAudit> list = page.getRecords();
        for (CarPackageAudit audit : list) {
            Long auditorId = audit.getAuditorId();
            if (auditorId != null) {
                User user = userService.get(auditorId);
                audit.setAuditorName(user.getUserName());
            }
        }
        page.setRecords(list);
        return new TablePage<CarPackageAudit>(page);
    }

    @Override
    public CarPackageAudit get(Long id) {
        CarPackageAudit audit = carPackageAuditMapper.selectById(id);
        Long auditorId = audit.getAuditorId();
        if (auditorId != null) {
            User user = userService.get(auditorId);
            audit.setAuditorName(user.getUserName());
        }
        return audit;
    }

    @Override
    public void deleteBatch(String ids) {
        Long[] dictIds = Convert.toLongArray(ids);
        for (Long dictId : dictIds) {
            carPackageAuditMapper.deleteById(dictId);
        }
    }

    @Override
    @Transactional
    public void startAudit(Long id, Long bpmnInfoId, Long director, Long finance, String info) {
        // 上架,非套餐,不是初始化或者重新提交状态不能发起审核
        ServiceItem serviceItem = serviceItemService.get(id);
        if (ServiceItem.SALESTATUS_ON.equals(serviceItem.getSaleStatus()) //上架状态
                || ServiceItem.CARPACKAGE_NO.equals(serviceItem.getCarPackage()) // 不是套餐
                || ServiceItem.AUDITSTATUS_AUDITING.equals(serviceItem.getAuditStatus())) { // 审核中
            throw new BusinessException("非法操作");
        }
        BpmnInfo bpmnInfo = bpmnInfoService.get(bpmnInfoId);
        // 创建CarPackageAudit对象
        CarPackageAudit audit = new CarPackageAudit();
        audit.setServiceItemId(serviceItem.getId());
        audit.setServiceItemInfo(serviceItem.getInfo());
        audit.setServiceItemPrice(serviceItem.getDiscountPrice());
        audit.setServiceItemName(serviceItem.getName());
        audit.setCreator(ShiroUtils.getUser().getUserName());
        audit.setInfo(info);
        audit.setCreateTime(new Date());
        audit.setBpmnInfoId(bpmnInfoId);
        audit.setBpmnInfo(bpmnInfo);
        // 持久化audit
        carPackageAuditMapper.insert(audit);
        // 启动流程实例
        HashMap<String, Object> params = new HashMap<>();
        params.put("director", director);
        params.put("finance", finance);
        params.put("discountPrice", serviceItem.getDiscountPrice().longValue());
        ProcessInstance instance = runtimeService.startProcessInstanceByKey(bpmnInfo.getActProcessKey(), String.valueOf(audit.getId()), params);
        // 更新CarPackageAudit对象
        audit.setInstanceId(instance.getProcessInstanceId());
        audit.setAuditorId(director);
        carPackageAuditMapper.updateById(audit);

        // 更新serviceItem审核状态
        serviceItemService.changeAuditStatus(id, ServiceItem.AUDITSTATUS_AUDITING);
    }

    @Override
    @Transactional
    public void cancelApply(Long id) {
        // 只有审核进行中才能撤销,审核通过或者审核拒接不能撤销
        CarPackageAudit audit = this.get(id);
        if (!CarPackageAudit.STATUS_IN_ROGRESS.equals(audit.getStatus())) {
            throw new BusinessException("非法操作");
        }

        // 设置audit对象的审批状态为撤销
        UpdateWrapper<CarPackageAudit> wrapper = Wrappers.<CarPackageAudit>update();
        wrapper.set("status",CarPackageAudit.STATUS_CANCEL);
        wrapper.set("auditor_id",null);
        wrapper.eq("id",id);
        carPackageAuditMapper.update(null,wrapper);
        // 删除流程实例对象
        runtimeService.deleteProcessInstance(audit.getInstanceId(), "撤销");
        // 将ServiceItem对象的审批状态设置为初始化
        Long serviceItemId = audit.getServiceItemId();
        serviceItemService.changeAuditStatus(serviceItemId, ServiceItem.AUDITSTATUS_REPLY);
    }

    @Override
    @Transactional
    public InputStream getDiagramAsStream(Long id) {
        CarPackageAudit audit = this.get(id);
        Long bpmnInfoId = audit.getBpmnInfoId();
        BpmnInfo bpmnInfo = bpmnInfoService.get(bpmnInfoId);
        ProcessDefinition definition = repositoryService.createProcessDefinitionQuery().processDefinitionId(bpmnInfo.getActProcessId()).singleResult();
        InputStream inputStream;
        BpmnModel bpmnModel = repositoryService.getBpmnModel(definition.getId());
        // 审核中则需要高亮
        if (CarPackageAudit.STATUS_IN_ROGRESS.equals(audit.getStatus())) {
            List<String> activeActivityIds = runtimeService.getActiveActivityIds(audit.getInstanceId());
            inputStream = new DefaultProcessDiagramGenerator().generateDiagram(bpmnModel, activeActivityIds, Collections.EMPTY_LIST,
                    "宋体", "宋体", "宋体");
        } else {
            inputStream = new DefaultProcessDiagramGenerator().generateDiagram(bpmnModel, Collections.EMPTY_LIST, Collections.EMPTY_LIST,
                    "宋体", "宋体", "宋体");
        }
        return inputStream;
    }

    @Override
    @Transactional
    public void audit(Long id, Integer auditStatus, String info) {
        CarPackageAudit audit = this.get(id);
        Long serviceItemId = audit.getServiceItemId();
        User user = ShiroUtils.getUser();
        // 必须是审批中才能审批,必须是审批人才能审批
        if (!CarPackageAudit.STATUS_IN_ROGRESS.equals(audit.getStatus()) && !user.getId().equals(audit.getAuditorId())) {
            throw new BusinessException("非法操作");
        }
        // info添加
        if (auditStatus.equals(CarPackageAudit.STATUS_PASS)) { // 审批通过
            info = audit.getInfo() + "<br>[" + user.getUserName() + "]审批通过:" + info;
        } else {
            info = audit.getInfo() + "<br>[" + user.getUserName() + "]审批拒绝:" + info;
        }
        audit.setInfo(info);

        // 设置参数
        String instanceId = audit.getInstanceId();
        runtimeService.setVariable(instanceId, "auditStatus", auditStatus);
        Task task = taskService.createTaskQuery().processInstanceId(instanceId).singleResult();

        // 执行流程
        taskService.complete(task.getId());
        audit.setAuditTime(new Date());

        // 审批通过
        if (auditStatus.equals(CarPackageAudit.STATUS_PASS)) {
            // 获取下一次的节点信息
            Task newTask = taskService.createTaskQuery().processInstanceId(instanceId).singleResult();
            if (newTask == null) { // 当没有下一个节点说明审批通过了
                audit.setStatus(CarPackageAudit.STATUS_PASS);
                // 审核通过没有当前审核人了
                audit.setAuditorId(null);
                audit.setAuditorName(null);
                serviceItemService.changeAuditStatus(serviceItemId, ServiceItem.AUDITSTATUS_APPROVED);
            } else {
                // 有下一个节点,说明还在审批中
                // 设置当前节点审批人
                audit.setAuditorId(Long.valueOf(newTask.getAssignee()));
            }
        } else {
            // 审批拒绝
            // 将流程定义列表的审批状态设置为审批拒绝
            audit.setStatus(CarPackageAudit.STATUS_REJECT);
            audit.setAuditorId(null);
            audit.setAuditorName(null);
            // 服务项目审批状态设置为重新提交
            serviceItemService.changeAuditStatus(serviceItemId, ServiceItem.AUDITSTATUS_REPLY);
        }
        carPackageAuditMapper.updateById(audit);
    }
}
